﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

using SGCG.Helpers;

using System.Diagnostics;

namespace SGCG.Model
{
    public class RegularPolygon : CompositeBorderedGraphicObject
    {
        private Line[] sideLines;
        private int sides;

        public RegularPolygon(GraphicObject parent, int sides) : base(parent)
        {
            Debug.Assert(sides >= 3);
            this.sides = sides;
            this.rawGraphicObjects = this.BuildObject().Cast<BorderedGraphicObject>().ToArray();
        }

        protected override IEnumerable<GraphicObject> BuildObject()
        {
            sideLines = new Line[sides];

            for (int i = 0; i < sideLines.Length; ++i)
                sideLines[i] = new Line(this)
                {
                    LineStyle = Model.LineStyle.Normal,
                    LineThickness = Model.LineThickness.Normal,
                    Color = Colors.Black
                };
            for (int i = 0; i < sideLines.Length; ++i)
                yield return sideLines[i];
        }

        // these properties become useless after the creation of the object...
        private int x;
        public int X
        {
            get { return x; }
            set { x = value; RecomputeInternalPoints(); }
        }

        private int y;
        public int Y
        {
            get { return y; }
            set { y = value; RecomputeInternalPoints(); }
        }

        private int radius;
        public int Radius
        {
            get { return radius; }
            set { radius = value; RecomputeInternalPoints(); }
        }

        private double angleInit;
        public double AngleInit
        {
            get { return angleInit; }
            set { angleInit = value; RecomputeInternalPoints(); }
        }

        private void RecomputeInternalPoints()
        {
            Point[] vertices = new Point[sides];
            double stepAngle = 2 * Math.PI / sides;
            Point P0 = new Point(X, Y);
            for (int i = 0; i < vertices.Length; ++i)
                vertices[i] = new Point(Math.Cos(i * stepAngle + angleInit), Math.Sin(i * stepAngle + angleInit)).Multiply(Radius).Add(P0);
            for (int i = 0; i < sideLines.Length; ++i)
            {
                sideLines[i].X1 = (int)Math.Round(vertices[i].X);
                sideLines[i].Y1 = (int)Math.Round(vertices[i].Y);
                sideLines[i].X2 = (int)Math.Round(vertices[(i+1)%sideLines.Length].X);
                sideLines[i].Y2 = (int)Math.Round(vertices[(i+1)%sideLines.Length].Y);
            }
        }

        public void ReceiveProperties(RegularPolygon other)
        {
            for (int i = 0; i < sideLines.Length; ++i)
            {
                sideLines[i] = (other.sideLines[i] as Line).CreateCopy() as Line;
                sideLines[i].Parent = this;
            }
            this.rawGraphicObjects = new List<BorderedGraphicObject>(this.sideLines).ToArray();
        }

        protected void CopyProperties(RegularPolygon other)
        {
            base.CopyProperties(other);
            other.ReceiveProperties(this);
        }

        public override GraphicObject CreateCopy()
        {
            RegularPolygon regularPolygon = new RegularPolygon(null, sides);
            CopyProperties(regularPolygon);
            return regularPolygon;
        }

        //public int ComputedX1 { get; private set; }
        //public int ComputedY1 { get; private set; }
        //public int ComputedX2 { get; private set; }
        //public int ComputedY2 { get; private set; }

        //private void Recompute()
        //{
        //    Point p1 = TransformPoint(new Point(X1, Y1));
        //    ComputedX1 = (int)Math.Round(p1.X);
        //    ComputedY1 = (int)Math.Round(p1.Y);
        //    Point p2 = TransformPoint(new Point(X2, Y2));
        //    ComputedX2 = (int)Math.Round(p2.X);
        //    ComputedY2 = (int)Math.Round(p2.Y);
        //}

        protected override Point GetBarycenter()
        {
            double xSum = 0, ySum = 0;
            for (int i = 0; i < sideLines.Length; ++i)
            {
                sideLines[i].Recompute();
                xSum += sideLines[i].ComputedX1 + sideLines[i].ComputedX2;
                ySum += sideLines[i].ComputedY1 + sideLines[i].ComputedY2;
            }
            return new Point(xSum / sideLines.Length / 2, ySum / sideLines.Length / 2);
        }
    }
}
